/*
 * Copyright (C) 2022 HiHope Open Source Organization .
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 *
 * limitations under the License.
 */

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "iot_gpio.h"
#include "hi_io.h"
#include "hi_time.h"
#include "iot_gpio_ex.h"
#include "iot_errno.h"
#include "iot_uart.h"
#include "iot_watchdog.h"
#include "ST7735.h"
//网络相关代码-----------start--------------------------------------------------
#include "lwip/sockets.h"
#include "wifi_connect.h"
#define _PROT_PC_ 8888
#define _PROT_HI_ 9999
#define TCP_BACKLOG 1//最多1个客户端连接
int sock_fd_hi,sock_fd_pc, new_fd_pc,new_fd_hi;
char recvbuf[4];					//接受客户端的数据，就是接受指令$$$$
//char startInstructions[4]="$$$$";   //接受指令$$$$,用于比较是否与接受的信息相同
char buf[50];                       //发送数据缓冲区，##id&title##
char id[20];                        //发送数据中的人脸标签号，可容纳9999人
char title[20];                     //发送数据中的条形码标签号
char box[5];                        //书框号
//服务端地址信息
struct sockaddr_in server_sock_pc;
struct sockaddr_in server_sock_hi;
//PC客户端地址信息
struct sockaddr_in client_sock_pc;
struct sockaddr_in *cli_addr_pc;
//Hi3861客户端地址信息
struct sockaddr_in client_sock_hi;
struct sockaddr_in *cli_addr_hi;
int sin_size;
ssize_t ret;
//网络相关代码-----------end----------------------------------------------------

//屏幕接线方式在ST7735.c文件中

#define Steer_Camera_Io 11
#define Steer_Platform_Io 12
#define Led_begin 14


#define Key_Io 10

#define COUNT 3
#define TASK_STAK_SIZE    (1024*30)
#define UART_BUFF_SIZE 100

#define WIFI_IOT_UART_IDX_1 1

unsigned int Steer_Camera_duty = 1400;
unsigned int Steer_Platform_duty = 1450;

unsigned int state = 0;

unsigned int flag = 0;
IotGpioValue Key;

static const char *state_stu = "0";
static const char *state_bok = "1";

uint8_t Send_data[30] = {0};
uint8_t Book_Str[20] = {0};
uint8_t Student_Str[20] = {0};

int numbox=0;
char buf[50];   
//发送数据缓冲区，##id&title##

//舵机响应函数
void set_angle(unsigned int duty,unsigned int num)
{
    unsigned int time = 20000;
    unsigned int i = 0;
    IoTGpioSetDir(num, IOT_GPIO_DIR_OUT);
    // for(i = 0;i<COUNT;i++)
    // {
        IoTGpioSetOutputVal(num, IOT_GPIO_VALUE1);
        hi_udelay(duty);
        IoTGpioSetOutputVal(num, IOT_GPIO_VALUE0);
        hi_udelay(time - duty);
    // }
}


//减速函数
void slow_down(unsigned int current_duty, unsigned int expect_duty,unsigned int num)
{
    if(current_duty == expect_duty)
    {
        set_angle(expect_duty,num); 
    }

    if(current_duty > expect_duty)
    {
        while(current_duty > expect_duty)
        { 
            for (int i = 0; i < COUNT; i++) 
            {
                set_angle(current_duty,num);   
                current_duty -= 25;  
            }
        }
        if(current_duty != expect_duty)
        {
            current_duty = expect_duty;
            for (int i = 0; i < COUNT; i++) 
            {
                set_angle(expect_duty,num);   
            }
        }
    }

    if(current_duty < expect_duty)
    {
        while(current_duty < expect_duty)
        {
            for (int i = 0; i < COUNT; i++) 
            {
                set_angle(current_duty,num);
                current_duty += 25;
            }
        }
        if(current_duty != expect_duty)
        {
            current_duty = expect_duty;
            for (int i = 0; i < COUNT; i++) 
            {
                set_angle(current_duty,num);   
            }
        }
    }
}

void steer_Camera_set_angle(int angle)//摄像头舵机
{
    unsigned int duty = 1500;
    unsigned int i = 0;
    duty += (angle*100/9);
    // slow_down(Steer_Camera_duty,duty,Steer_Camera_Io);
    // Steer_Camera_duty = duty;   
    for(i = 0;i<20;i++)
        set_angle(duty,Steer_Camera_Io); 
}

void steer_platform_set_angle(int angle)//平台舵机
{
    unsigned int duty = 1500;
    unsigned int i = 0;
    duty +=(angle*100/9);    
    // slow_down(Steer_Platform_duty,duty,Steer_Platform_Io);
    for(i = 0; i<20 ; i++)
        set_angle(duty,Steer_Platform_Io); 
}


unsigned char check_msg(uint8_t *uart_buff_ptr,unsigned int length)
{
    unsigned char j = 0;
    unsigned char num = 0;

    if(state == 1)
    {
        if((uart_buff_ptr[0] == '#') && (uart_buff_ptr[1] == '#'))
        {
            printf("Recv_student_num!\n");
            for(j = 4;j<length;j++)
            {
                Student_Str[num++] = uart_buff_ptr[j];
            }
            return 1;
        }
    }
    else if(state == 3)
    {
        if((uart_buff_ptr[0] == '*') && (uart_buff_ptr[1] == '*'))
        {
            printf("Recv_Book_num!\n");
            for(j = 2;j<length;j++)
            {
                Book_Str[num++] = uart_buff_ptr[j];
            }
            return 1;
        }
    }
    return 0;
}

void system_init()
{
    IoSetFunc(IOT_IO_NAME_GPIO_13,IOT_IO_FUNC_GPIO_13_GPIO);
    IoTGpioSetDir(IOT_IO_NAME_GPIO_13,IOT_GPIO_DIR_IN);
    IoSetPull(IOT_IO_NAME_GPIO_13,IOT_IO_PULL_UP); 
    
    IoSetFunc(IOT_IO_NAME_GPIO_14,IOT_IO_FUNC_GPIO_14_GPIO);
    IoTGpioSetDir(Led_begin, IOT_GPIO_DIR_OUT);
    IoTGpioSetDir(Led_begin, IOT_GPIO_VALUE1);

    TFTSPI_Init(0); 
    TFTSPI_CLS(u16WHITE); //清屏
    steer_platform_set_angle(0);
    steer_Camera_set_angle(0);


}

/* 任务实现 */
void RobotTask(void* parame)
{
    (void)parame;
    uint8_t uart_buff[UART_BUFF_SIZE] = { 0 };
    uint8_t *uart_buff_ptr = uart_buff;
    unsigned int duty = 500;
    unsigned int recv_num = 0;
    unsigned int j = 0;
    // unsigned char box_num = 0;


    //网络连接初始化-------------------------start------------------------
    //连接Wifi
	WifiConnect("Fle", "gxd001213");
	//创建socket
	if ((sock_fd_pc = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("socket is error\r\n");
		exit(1);
	}
	if ((sock_fd_hi = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("socket is error\r\n");
		exit(1);
	}
	//PC的服务端
	bzero(&server_sock_pc, sizeof(server_sock_pc));
	server_sock_pc.sin_family = AF_INET;
	server_sock_pc.sin_addr.s_addr = htonl(INADDR_ANY);
	server_sock_pc.sin_port = htons(_PROT_PC_);
	//Hi的服务端
	bzero(&server_sock_hi, sizeof(server_sock_hi));
	server_sock_hi.sin_family = AF_INET;
	server_sock_hi.sin_addr.s_addr = htonl(INADDR_ANY);
	server_sock_hi.sin_port = htons(_PROT_HI_);
	//调用bind函数绑定socket和地址
	if (bind(sock_fd_pc, (struct sockaddr *)&server_sock_pc, sizeof(struct sockaddr)) == -1)
	{
		perror("pc bind is error\r\n");
		exit(1);
	}
	if (bind(sock_fd_hi, (struct sockaddr *)&server_sock_hi, sizeof(struct sockaddr)) == -1)
	{
		perror("hi bind is error\r\n");
		exit(1);
	}
	//调用listen函数监听(指定port监听)
	if (listen(sock_fd_pc, TCP_BACKLOG) == -1)
	{
		perror("listen pc is error\r\n");
		exit(1);
	}
	if (listen(sock_fd_hi, TCP_BACKLOG) == -1)
	{
		perror("listen hi is error\r\n");
		exit(1);
	}
	printf("start accept\n");
    //以下为等待连接，只有两个客户端都连接了整个系统才能开始工作
    sin_size = sizeof(struct sockaddr_in);
    if ((new_fd_hi = accept(sock_fd_hi, (struct sockaddr *)&client_sock_hi, (socklen_t *)&sin_size)) == -1)
    {
        perror("hi accept");
        //continue;
    }
    cli_addr_hi = malloc(sizeof(struct sockaddr));
    printf("hi accept addr\r\n");
    if (cli_addr_hi != NULL)
    {
        memcpy(cli_addr_hi, &client_sock_hi, sizeof(struct sockaddr));
    }
    if ((new_fd_pc = accept(sock_fd_pc, (struct sockaddr *)&client_sock_pc, (socklen_t *)&sin_size)) == -1)
    {
        perror("pc accept");
        //continue;
    }
    cli_addr_pc = malloc(sizeof(struct sockaddr));
    printf("pc accept addr\r\n");
    if (cli_addr_pc != NULL)
    {
        memcpy(cli_addr_pc, &client_sock_pc, sizeof(struct sockaddr));
    }
    printf("connect all success\n");
    //网络连接初始化------------------------end--------------------------------
    IoSetFunc(IOT_IO_NAME_GPIO_0,IOT_IO_FUNC_GPIO_0_UART1_TXD);//
    IoSetFunc(IOT_IO_NAME_GPIO_1,IOT_IO_FUNC_GPIO_1_UART1_RXD);//
    IotUartAttribute uart_attr = {

        // baud_rate: 9600
        .baudRate = 115200,

        // data_bits: 8bits
        .dataBits = 8,
        .stopBits = 1,
        .parity = 0,
    };
    // // // Initialize uart driver
    IoTUartInit(WIFI_IOT_UART_IDX_1, &uart_attr);
    IoTWatchDogDisable();
    system_init();
    //不能动

    //此处可加接收PC端的启动命令

    while(flag)
    {
        switch(state)
        {
            case 0: 
                {
                    IoTGpioSetDir(Led_begin, IOT_GPIO_VALUE1);//14亮
                    TFTSPI_P32x32Str(0,1,"智慧还书端",10,u16BLACK,u16WHITE);//字符串显示
                    TFTSPI_P16x16Str(3,6,"开始还书",8,0,u16BLUE,u16WHITE);		//字符串显示
                    IoTGpioGetInputVal(Key_Io, &Key);//按键，未按下为高电平
                    while(Key)
                    {
                        IoTGpioGetInputVal(Key_Io, &Key);
                    }
                    TFTSPI_P16x16Str(3,6,"部分清屏",8,4,u16BLUE,u16WHITE);		//字符串显示
                    TFTSPI_P16x16Str(3,6,"正在还书",8,5,u16BLUE,u16WHITE);		//字符串显示
                    IoTGpioSetDir(Led_begin, IOT_GPIO_VALUE0);//14灭 
                    state = 1;
                    IoTUartRead(WIFI_IOT_UART_IDX_1, uart_buff_ptr, UART_BUFF_SIZE);
                    for(j = recv_num;j<UART_BUFF_SIZE;j++)
                    {
                        uart_buff_ptr[j] = '\0';
                    }
                    IoTUartWrite(WIFI_IOT_UART_IDX_1, (unsigned char *)state_stu, strlen(state_stu));
                }
            break;
            //case1:等待接收上位机信息,鉴别并发送信息到PC端

            //等待收到人像信息
            case 1:
                    recv_num = IoTUartRead(WIFI_IOT_UART_IDX_1, uart_buff_ptr, UART_BUFF_SIZE);
                     if(recv_num)
                     {
                        printf("Uart1 read data:%d\n", recv_num);
                        // *uart_buff_ptr[i] = '\0';
                        for(j = recv_num;j<UART_BUFF_SIZE;j++)
                        {
                            uart_buff_ptr[j] = '\0';
                        }
                        printf("Uart1 read data:%s\n", uart_buff_ptr);
                        if(check_msg(uart_buff_ptr,recv_num))
                        {
                            state = 2;
                        }
                     //收到人像信息并进行鉴码，见check_msg
                     }
            break;                   

            case 2:
                steer_Camera_set_angle(89);
                hi_udelay(1000000);
                state = 3;       
                recv_num = IoTUartRead(WIFI_IOT_UART_IDX_1, uart_buff_ptr, UART_BUFF_SIZE);
                for(j = 0;j<recv_num;j++)
                {
                    uart_buff_ptr[j] = '\0';
                }
                //转动摄像头向下看，同时先清空串口接收的字符串数组
                IoTUartWrite(WIFI_IOT_UART_IDX_1, (unsigned char *)state_bok, strlen(state_stu));
            break;

            case 3:
                    recv_num = IoTUartRead(WIFI_IOT_UART_IDX_1, uart_buff_ptr, UART_BUFF_SIZE);
                     if(recv_num)
                     {
                        printf("Uart1 read data:%d\n", recv_num);
                        // *uart_buff_ptr[i] = '\0';
                        for(j = recv_num;j<UART_BUFF_SIZE;j++)
                        {
                             uart_buff_ptr[j] = '\0';
                        }
                        printf("Uart1 read data:%s\n", uart_buff_ptr);
                        if(check_msg(uart_buff_ptr,recv_num))
                        {
                            state = 4;
                        }
                     }
                    //接收书号信息，并进行鉴码
            break;                   

            case 4:
                    steer_Camera_set_angle(0); 
                    TFTSPI_CLS(u16WHITE); //清屏
                    TFTSPI_P16x16Str(3,1,"还书信息",8,6,u16BLUE,u16WHITE);                    
                    TFTSPI_P16x16Str(0,2,"学号：",6,1,u16BLUE,u16WHITE);		//字符串显示
                    j = 0;
                    while (Student_Str[j] != '\0')
                    {
                        TFTSPI_P8X8(7+j, 5, Student_Str[j++],u16BLACK,u16WHITE);
                    }

                    TFTSPI_P16x16Str(0,5,"书号：",6,2,u16BLUE,u16WHITE);		//字符串显示
                    j = 0;
                    while (Book_Str[j] != '\0')
                    {
                        TFTSPI_P8X8(7+j, 11, Book_Str[j++],u16BLACK,u16WHITE);
                    }
                    TFTSPI_P16x16Str(3,7,"确认还书：",8,3,u16BLUE,u16WHITE);		//字符串显示
                    IoTGpioGetInputVal(Key_Io, &Key);
                    while(Key)
                    {
                        IoTGpioGetInputVal(Key_Io, &Key);
                    }
                    state = 5; 

                    //摄像头转回水平，再次按按键即确认还书 
            break;

            case 5:
                    steer_platform_set_angle(-45);
                    TFTSPI_CLS(u16WHITE); //清屏
                    //1.开始发送数据，看情况加delay，预留足够的滑动时间；2.根据书目信息，在这里自动判别是哪个框，将框号，学号，书号先整理成一份数据，然后发送，
                    //发送格式为：（信息位位数）#（框号1位）&（学号11位）&（书号8位）#
                    //发送给Hi3861客户端------------------------------
                    int numbox=0;
                    if(Book_Str[12]=='2')
                    {
                        numbox=1;
                    }
                    else if(Book_Str[12]=='6')
                    {
                        numbox=2;
                    }
                    else if(Book_Str[12]=='5')
                    {
                        numbox=3;
                    }
                    sprintf(buf,"29#%d&%s&%s#",numbox,Student_Str,Book_Str);
                    printf("Uart1 Recv data:%s\n", buf);

                    // 发送给Qt客户端------------------------------
                    if ((ret = send(new_fd_pc, buf, strlen(buf)+1, 0)) == -1)
                    {
                        perror("send : ");
                    }
                    sprintf(buf,"29#%d&%s&%s#",numbox,Student_Str,Book_Str);
                    printf("Uart1 Recv data:%s\n", buf);
                    
                    if ((ret = send(new_fd_hi, buf, strlen(buf)+1, 0)) == -1)
                    {
                        perror("send : ");
                    }

                    // 发送结束----------------------------------------------------------------
                    steer_platform_set_angle(0);
                    state = 0;
                    //确认还书后平台，循环一次
            break;
        }
    
    }
}



static void RobotDemo(void)
{
    osThreadAttr_t attr;

    attr.name = "RobotTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = TASK_STAK_SIZE;
    attr.priority = osPriorityNormal;

    if (osThreadNew(RobotTask, NULL, &attr) == NULL) {
        printf("[RobotDemo] Falied to create RobotTask!\n");
        flag = 0;
    }
    {
        flag = 1;
    }
}

APP_FEATURE_INIT(RobotDemo);
